#include <iostream>
#include <pthread.h>
#include <unistd.h>

using namespace std;

// 读写锁
// 读写锁是一种用于控制多个线程对共享数据进行访问的同步机制，它比普通的互斥锁更灵活
// 读锁（共享锁）：允许多个线程同时读数据
// 写锁（独占锁）：在写数据时，只有一个线程可以进行写操作，并且在写操作时，其他线程不能进行读或写操作
pthread_rwlock_t g_rwlock;

// 共享全局数据
int g_cnt = 100;

// 线程 1
// 这个线程是一个读者线程。它进入一个无限循环，在每次循环中：
// 使用 pthread_rwlock_rdlock(&g_rwlock) 获得读锁
// 读锁允许多个线程同时读取共享数据（g_cnt），但不允许写线程同时写数据
// 读锁加锁后，打印 "here" 并让线程休眠 10 秒，这意味着线程1持有读锁长达10秒
// 打印 g_cnt 的值以及当前线程的ID
// 最后使用 pthread_rwlock_unlock(&g_rwlock) 解锁，让其他读或写操作可以进行
// 注意：由于它持有锁的时间较长（10秒），其他读写线程在这段时间内可能会阻塞等待
void *thread_func1(void *arg)
{
    while (1)
    {
        // 加锁（读锁）
        pthread_rwlock_rdlock(&g_rwlock);
        cout << "here" << endl;
        sleep(10);
        printf("thread1 Id: %lu, g_cnt: %d\n", pthread_self(), g_cnt);
        pthread_rwlock_unlock(&g_rwlock);
    }

    // 退出线程
    pthread_exit(NULL);
}

// 线程 2
// 这个线程也是一个读者线程，执行读操作。其行为和 thread_func1 类似，但有一些不同：
// 它首先休眠 100 秒，这意味着线程2将在主线程启动后 100 秒才开始读取操作
// 每次读取时，它使用 pthread_rwlock_rdlock(&g_rwlock) 加锁后，立即打印 g_cnt 值和线程ID
// 然后调用 pthread_rwlock_unlock(&g_rwlock) 解锁
// 每次读取后，它只休眠 100 微秒（usleep(100)），这意味着它会频繁读取数据
void *thread_func2(void *arg)
{
    sleep(100);
    while (1)
    {
        // 加锁（读锁）
        pthread_rwlock_rdlock(&g_rwlock);
        printf("thread2 Id: %lu, g_cnt: %d\n", pthread_self(), g_cnt);
        pthread_rwlock_unlock(&g_rwlock);
        usleep(100);
    }

    // 退出线程
    pthread_exit(NULL);
}

// 线程 3
// 这是一个写者线程，负责更新 g_cnt 的值。它的行为如下：
// 首先休眠 1 毫秒（usleep(1000)），确保它稍后于其他线程启动
// 无限循环中，它使用 pthread_rwlock_wrlock(&g_rwlock) 获得写锁。写锁会阻止其他读者和写者线程进行任何操作，直到它解锁
// 它将 g_cnt 增加 66，然后打印新的 g_cnt 值和线程ID
// 使用 pthread_rwlock_unlock(&g_rwlock) 解锁，让其他线程可以进行读写操作
// 注意：因为写锁是独占的，线程3在持有写锁期间，任何读者或其他写者都无法访问共享数据
void *thread_func3(void *arg)
{
    usleep(1000);
    while (1)
    {
        // 加锁（写锁）
        pthread_rwlock_wrlock(&g_rwlock);
        g_cnt += 66;
        printf("thread3 Id: %lu, g_cnt: %d\n", pthread_self(), g_cnt);
        pthread_rwlock_unlock(&g_rwlock);
    }

    // 退出线程
    pthread_exit(NULL);
}

// 线程 4
// 这个线程在启动后立即调用 pthread_exit(NULL) 退出
// 它对共享数据没有任何操作，也没有使用锁
void *thread_func4(void *arg)
{
    // 退出线程
    pthread_exit(NULL);
}

// 主线程的任务是初始化读写锁，并创建四个线程。
// 然后进入一个无限循环，保证主线程不会退出，这样所有子线程可以持续运行。
// 主线程不会直接参与读写操作，但负责创建线程和管理锁的生命周期
int main()
{
    // 初始化读写锁
    pthread_rwlock_init(&g_rwlock, NULL);

    pthread_t tid1;
    pthread_create(&tid1, NULL, thread_func1, NULL);

    pthread_t tid2;
    pthread_create(&tid2, NULL, thread_func2, NULL);

    pthread_t tid3;
    pthread_create(&tid3, NULL, thread_func3, NULL);

    pthread_t tid4;
    pthread_create(&tid4, NULL, thread_func4, NULL);

    while (1)
    {
        sleep(1);
    }

    // 销毁读写锁
    pthread_rwlock_destroy(&g_rwlock);

    return 0;
}